﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml.Linq;
using LeoK.TM.Entity;
using MySql.Data.MySqlClient;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
using Telerik.Windows.Input.Touch;
using Telerik.Windows.Persistence;
using FontFamily = System.Windows.Media.FontFamily;
using GridViewColumn = Telerik.Windows.Controls.GridViewColumn;

namespace LeoK.Common
{
    public class LeoKDataGrid<T> : RadGridView 
                 where T:new()
    {
        private XElement _settingRoot;

        public Func<GridViewAutoGeneratingColumnEventArgs, bool> BeforeGeneratingColumn;
        public Action<T> BeforeSaveData;

        public LeoKDataGrid()
        {
            NewRowPosition = GridViewNewRowPosition.Bottom;
            GroupRenderMode = GroupRenderMode.Flat;
            ShowGroupPanel = false;
            CanUserDeleteRows = true;
            FontFamily = new FontFamily("SimSun");
            FontSize = 12;
            GridLinesVisibility = GridLinesVisibility.Both;
            
            RowEditEnded += OnRowEditEnded;
            Deleting += OnDeleting;
            Unloaded += OnUnloaded;
            LoadSetting();            
        }

        private void LoadSetting()
        {
            string name = typeof(T).FullName;
            PersistenceManager manager = new PersistenceManager();
            if (File.Exists(@"Setting\" + name))
            {
                using (FileStream fs = new FileStream(@"Setting\" + name, FileMode.Open))
                {
                    _settingRoot = XElement.Load(fs);
                    fs.Close();
                }
            }
        }
        
        private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
        {
            string name = typeof (T).FullName;
            if (!Directory.Exists("Setting"))
            {
                Directory.CreateDirectory("Setting");
            }

            XElement root = new XElement("Setting");

            foreach (GridViewColumn column in Columns)
            {
                XElement el = new XElement(column.UniqueName);
                el.Add(new XAttribute("Width", column.ActualWidth));
                el.Add(new XAttribute("DisplayIndex", column.DisplayIndex));
                root.Add(el);
            }

            using (FileStream fs = new FileStream(@"Setting\" + name, FileMode.OpenOrCreate))
            {
                fs.SetLength(0);
                root.Save(fs);
                fs.Flush(true);
                fs.Close();
            }
        }

        private void OnDeleting(object sender, GridViewDeletingEventArgs e)
        {
            e.Cancel = true;
            T item = (T) e.Items.ToList()[0];
            RadWindow.Confirm("确定删除该条记录吗？", async (obj, result) =>
            {
                if (result.DialogResult.HasValue)
                {
                    using (MySqlDB mySqlDb = new MySqlDB())
                    {
                        int id = (int)item.GetType().GetProperty("ID").GetValue(item);
                        await mySqlDb.ExecuteNonQuery("DELETE FROM " + item.GetType().Name + " WHERE ID=" + id, null);
                        (ItemsSource as ObservableCollection<T>).Remove(item);
                    }
                }
            });
        }

        private void OnRowEditEnded(object sender, GridViewRowEditEndedEventArgs e)
        {
            T obj = (T)e.EditedItem;
            if (BeforeSaveData != null)
            {
                BeforeSaveData(obj);
            }

            using (MySqlDB mySqlDb = new MySqlDB())
            {
                mySqlDb.UpdateObj(obj);
            }
        }

        public async override void OnAddingNewDataItem(GridViewAddingNewEventArgs e)
        {
            T newObj = new T();
            using (MySqlDB mySqlDb = new MySqlDB())
            {
                int id = (int)await mySqlDb.InsertObj(newObj);
                PropertyInfo propertyInfo = newObj.GetType().GetProperty("ID");
                if (propertyInfo != null)
                {
                    propertyInfo.SetValue(newObj, id);
                }
            }

            e.NewObject = newObj;
            base.OnAddingNewDataItem(e);
        }

        protected override void OnAutoGeneratingColumn(GridViewAutoGeneratingColumnEventArgs e)
        {
            base.OnAutoGeneratingColumn(e);

            if (BeforeGeneratingColumn == null || !BeforeGeneratingColumn(e))
            {
                if (e.Column is GridViewDataColumn)
                {
                    GridViewDataColumn col = e.Column as GridViewDataColumn;
                    if (col.DataType == typeof (DateTime))
                    {
                        col.DataFormatString = "yyyy/MM/dd HH:mm";
                    }
                    else if (col.DataType.IsEnum)
                    {
                        GridViewComboBoxColumn cmbCol = new GridViewComboBoxColumn();
                        cmbCol.UniqueName = col.UniqueName;
                        cmbCol.Header = ((typeof (T).GetProperty(col.UniqueName).GetCustomAttribute(typeof (DisplayAttribute)) as DisplayAttribute)).Name;

                        cmbCol.IsComboBoxEditable = false;
                        cmbCol.DisplayMemberPath = "Value";
                        cmbCol.SelectedValueMemberPath = "Key";
                        cmbCol.ItemsSource = TransEnum(col.DataType);

                        e.Column = cmbCol;
                    }
                    else if (col.DataType.Name == "Boolean")
                    {
                        GridViewCheckBoxColumn chkViewCheckBox = new GridViewCheckBoxColumn();
                        chkViewCheckBox.UniqueName = col.UniqueName;
                        chkViewCheckBox.Header = ((typeof(T).GetProperty(col.UniqueName).GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute)).Name;

                        e.Column = chkViewCheckBox;
                    }
                }
            }

            e.Column.IsFilterable = false;
            EBAttribute ebAttribute = (EBAttribute) (typeof (T).GetProperty(e.Column.UniqueName)).GetCustomAttribute(typeof (EBAttribute));
            if (ebAttribute != null)
            {
                e.Column.IsReadOnly = ebAttribute.IsReadOnly;
                e.Column.IsFilterable = ebAttribute.AllowFilter;

                if (ebAttribute.DataConverter != null && e.Column is GridViewDataColumn)
                {
                    (e.Column as GridViewDataColumn).DataMemberBinding.Converter = (IValueConverter)ebAttribute.DataConverter.Assembly.CreateInstance(ebAttribute.DataConverter.FullName);
                }

            }
            if (_settingRoot != null)
            {
                if (_settingRoot.Element(e.Column.UniqueName) != null)
                {
                    e.Column.Width = double.Parse(_settingRoot.Element(e.Column.UniqueName).Attribute("Width").Value);
                    e.Column.DisplayIndex = Int32.Parse(_settingRoot.Element(e.Column.UniqueName).Attribute("DisplayIndex").Value);
                }
            }
        }

        public async void LoadData(string filter = "", List<MySqlParameter> paras = null) 
        {
            using (MySqlDB mySqlDb = new MySqlDB())
            {
                ObservableCollection<T> dataSources = new ObservableCollection<T>(await mySqlDb.QueryObjs<T>("SELECT * FROM " + typeof(T).Name + filter, paras));
                ItemsSource = dataSources;
            }
        }

        private Dictionary<object, string> TransEnum(Type enumType)
        {
            Dictionary<object, string> result = new Dictionary<object, string>();
            foreach (object item in Enum.GetValues(enumType))
            {
                result[item] = item.ToString();
            }

            return result;
        } 
    }

    public class ColorPickerColumn : GridViewBoundColumnBase
    {
        public override FrameworkElement CreateCellEditElement(GridViewCell cell, object dataItem)
        {
            this.BindingTarget = RadColorPicker.SelectedColorProperty;

            RadColorPicker picker = new RadColorPicker();
            picker.MainPalette = ColorPreset.Opulent;
            picker.Margin = new Thickness(-1);
            picker.Width = cell.ActualWidth;
            picker.Height = cell.ActualHeight;
            TouchManager.SetIsTouchHitTestVisible(picker, false);
            picker.SetBinding(this.BindingTarget, this.CreateValueBinding());

            return picker;
        }

        protected override void RefreshCellElement(FrameworkElement element, DependencyProperty dependencyProperty)
        {
            base.RefreshCellElement(element, dependencyProperty);
        }

        public override FrameworkElement CreateCellElement(GridViewCell cell, object dataItem)
        {
            TM_Sln sl = dataItem as TM_Sln;
            if (sl.ColorFlag == "")
            {
                sl.ColorFlag = "#00000000";
            }
            FrameworkElement el = base.CreateCellElement(cell, dataItem);
            (el as TextBlock).Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(sl.ColorFlag));
            (el as TextBlock).Text = "";
            el.Margin = new Thickness(0);
            return el;
        }

        public override object GetNewValueFromEditor(object editor)
        {
            RadColorPicker picker = editor as RadColorPicker;

            return base.GetNewValueFromEditor(editor);
        }

        private Binding CreateValueBinding()
        {
            Binding valueBinding = new Binding();
            valueBinding.Mode = BindingMode.TwoWay;
            valueBinding.NotifyOnValidationError = true;
            valueBinding.ValidatesOnExceptions = true;
            valueBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
            valueBinding.Path = new PropertyPath(this.DataMemberBinding.Path.Path);

            return valueBinding;
        }
    }
}
